﻿using log4net;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;

namespace ScreenshotViewer
{
    static class Program
    {
        private static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            var downloader = new Thread(new ThreadStart(DownloadPageImages));
            downloader.Priority = ThreadPriority.Lowest;
            downloader.Start();
            Application.Run(new Viewer());
        }

        private static void DownloadPageImages()
        {
            Log.Debug("Enter");
            const string uri = "https://forums.frontier.co.uk/showthread.php/95490-Screenie(s)";
            var firstPage = GetFirstPage(uri);
            var lastPageNumber = GetLastPageNumber(firstPage);
            for (int i = 1; i < lastPageNumber + 1; i++)
            {
                var page = GetPage(uri, i);
                if (string.IsNullOrWhiteSpace(page))
                {
                    return;
                }

                var doc = new HtmlAgilityPack.HtmlDocument();
                doc.LoadHtml(page);
                foreach (var image in doc.DocumentNode.Descendants("img"))
                {
                    var src = image.Attributes["src"].Value.ToLowerInvariant();
                    if (src.Contains("i.imgur.com") ||
                        src.Contains("attachment.php") ||
                        src.Contains("inara.cz/data/gallery"))
                    {
                        src = image.Attributes["src"].Value;
                        src = src.StartsWith("attachment.php") ? $"{uri}/{src}" : src;
                        var bytesDownloaded = DownloadImage(src);
                        if (bytesDownloaded <= 2048)
                        {
                            Log.Warn($"Imagesize for [{src}]:[{bytesDownloaded}] is smaller than expected");
                        }
                    }
                }

                Thread.Sleep((int)TimeSpan.FromSeconds(5).TotalMilliseconds);
            }
        }

        private static int GetLastPageNumber(string firstPage)
        {
            var doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(firstPage);
            var lastPageLink = doc.DocumentNode.Descendants("a")
                .Where(p => p.GetAttributeValue("title", "").StartsWith("Last Page"))
                .FirstOrDefault();
            var re = new Regex(@"page([\d]+)");
            var lastPageMatch = re.Match(lastPageLink.Attributes["href"].Value);
            Log.Debug($"Last page number found:[{lastPageMatch.Success}]");
            return int.Parse(lastPageMatch.Groups[1].Value);
        }

        private static long DownloadImage(string uri)
        {
            Log.Debug($"DownloadImage:[{uri}]");
            var folder = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
            var fileName = Path.Combine(folder, GetSafeFileName(uri));
            if (!File.Exists(fileName))
            {
                try
                {
                    using (var wc = new WebClient())
                    {
                        uri = WebUtility.HtmlDecode(uri);
                        wc.DownloadFile(uri, fileName);
                        var fi = new FileInfo(fileName);
                        Log.Debug($"Imagesize for [{uri}]:[{fi.Length}]");
                        return fi.Length;
                    }
                }
                catch (Exception ex)
                {
                    Log.Error($"Image could not be downloaded from [{uri}]", ex);
                    return 0L;
                }
            }
            else
            {
                return new FileInfo(fileName).Length;
            }
        }

        private static string GetFirstPage(string uri)
        {
            Log.Debug($"Downloading page from [{uri}]");
            try
            {
                using (var wc = new WebClient())
                {
                    var page = wc.DownloadString(uri);
                    Log.Debug($"{page.Length} bytes downloadded from [{uri}]");
                    return page;
                }
            }
            catch (Exception ex)
            {
                Log.Error($"GetFirstPage failed for uri:[{uri}]", ex);
            }

            return null;
        }

        private static string GetPage(string uri, int pageNumber)
        {
            string appFolder = GetAppFolder();
            if (pageNumber > 1)
            {
                uri += $"/page{pageNumber}";
            }

            try
            {
                var fileName = Path.Combine(appFolder, GetSafeFileName(uri) + ".html");
                if (!File.Exists(fileName))
                {
                    using (var wc = new WebClient())
                    {
                        var page = wc.DownloadString(uri);
                        File.WriteAllText(fileName, page);
                        Log.Debug($"{page.Length} bytes downloaded. Page [{uri}] saved to:[{fileName}]");
                        return page;
                    }
                }

                return File.ReadAllText(fileName);
            }
            catch (Exception ex)
            {
                Log.Error("GetPage failed for uri:[{uri}]", ex);
            }

            return null;
        }

        private static string GetAppFolder()
        {
            var folder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
            var appName = Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().Location);
            var appFolder = Path.Combine(folder, appName);
            if (!Directory.Exists(appFolder))
            {
                Directory.CreateDirectory(appFolder);
            }

            return appFolder;
        }

        private static string GetSafeFileName(string uri)
        {
            var re = new Regex(@"[;:/\?=&]");
            return re.Replace(uri, "_");
        }
    }
}